package net.qiqbframework.modelling.command;


import lombok.Getter;
import net.qiqbframework.commandhandling.CommandBus;
import net.qiqbframework.commandhandling.CommandHandlerNotFoundException;
import net.qiqbframework.commandhandling.CommandMessage;
import net.qiqbframework.commandhandling.CommandMessageHandler;
import net.qiqbframework.common.Registration;
import net.qiqbframework.messaging.annotation.*;
import net.qiqbframework.messaging.task.CurrentMessageTask;
import net.qiqbframework.modelling.command.fetching.AggregateCommandModel;
import net.qiqbframework.modelling.command.fetching.PreAnnotatedCommand;
import net.qiqbframework.modelling.command.fetching.PreAnnotatedCommandModel;
import net.qiqbframework.modelling.command.handling.BusinessMessage;
import net.qiqbframework.modelling.command.handling.BusinessMessageExecutableHandler;
import net.qiqbframework.modelling.command.handling.GenericBusinessMessage;
import net.qiqbframework.modelling.domain.*;
import net.qiqbframework.modelling.repository.Repository;
import net.qiqbframework.serialization.SerializedObject;
import net.qiqbframework.serialization.Serializer;

import java.util.*;

/**
 * 内部注解处理
 *
 * @param <C>
 * @param <A>
 */
public class InnerAnnotationCommandHandler<C, A> implements CommandMessageHandler {

    private final Class<C> commandType;

    private AggregateCommandModel<C, A> aggregateCommandModel;

    private final Repository<A> repository;


    private final Map<String, Set<CommandMessageHandler>> supportedCommandsByName;

    @Getter
    private final AggregateModel<A> aggregateModel;


    private final AggregateHandlingMonitor aggregateHandlingMonitor;

    private final Serializer aggregateRootSerializer;
    private final HandlerParameterResolverFactory parameterResolverFactory;
    private final MessageHandlingMemberFactory handlerDefinition;

    protected InnerAnnotationCommandHandler(InnerAnnotationCommandHandlerBuilder<C, A> builder) {

        builder.validate();

        this.repository = builder.repository;
        this.commandType = builder.commandType;
        this.aggregateHandlingMonitor = builder.aggregateHandlingMonitor();
        this.aggregateRootSerializer = builder.aggregateRootSerializer();

        this.handlerDefinition = builder.handlerDefinition;
        this.parameterResolverFactory = builder.parameterResolverFactory;
        this.supportedCommandsByName = new HashMap<>();
        AggregateModel<A> aggregateModel = builder.buildAggregateModel();
        this.aggregateModel = aggregateModel;
        this.aggregateCommandModel = new PreAnnotatedCommandModel<>(commandType, repository, parameterResolverFactory, handlerDefinition);
        initializeHandlers();

    }


    public Registration subscribe(CommandBus commandBus) {
        List<Registration> subscriptions = supportedCommandsByName.entrySet().stream()
                // flatMap
                .flatMap(entry -> entry.getValue().stream().map(messageHandler -> commandBus.subscribe(entry.getKey(), this)))
                // filter
                .filter(Objects::nonNull).toList();
        return () -> subscriptions.stream().map(Registration::cancel).reduce(Boolean::logicalOr).orElse(false);
    }

    private void initializeHandlers() {
        AnnotatedHandlerInspector<C> inspector = AnnotatedHandlerInspector.inspectType(commandType,
                parameterResolverFactory,
                HandlerAttributesPostProcessor.EMPTY,
                handlerDefinition);
        // 汇总多个执行器
        for (Map.Entry<Class<?>, SortedSet<MessageExecutableHandler>> handlersPerType : inspector.getAllHandlers().entrySet()) {

            for (MessageExecutableHandler handler : handlersPerType.getValue()) {
                initializeHandler(handler);
            }
        }
    }


    private void initializeHandler(MessageExecutableHandler handler) {

        handler.unwrap(BusinessMessageExecutableHandler.class).ifPresent(cmh -> {
            CommandMessageHandler messageHandler;
            messageHandler = new AggregateCommandHandler(cmh);
            supportedCommandsByName.computeIfAbsent(cmh.commandNaming(), key -> new HashSet<>()).add(messageHandler);
        });

    }

    @Override
    public Object handle(CommandMessage<?> commandMessage) throws Exception {
        final Set<CommandMessageHandler> commandMessageHandlers = supportedCommandsByName.get(commandMessage.getCommandName());
        if (commandMessageHandlers == null || commandMessageHandlers.isEmpty()) {
            throw new CommandHandlerNotFoundException(commandMessage);
        }
        return commandMessageHandlers.stream().findFirst().get().handle(commandMessage);
    }


    private class AggregateCommandHandler implements CommandMessageHandler {

        private final BusinessMessageExecutableHandler handler;

        public AggregateCommandHandler(BusinessMessageExecutableHandler handler) {
            this.handler = handler;
        }

        @Override
        public Object handle(CommandMessage<?> commandMessage) throws Exception {
            // 创建命令
            PreAnnotatedCommand<C, A> command = new PreAnnotatedCommand<>((C) commandMessage.getPayload(), aggregateCommandModel);

            Aggregate<A> aggregate = command.obtainAggregate().orElseThrow(() -> new AggregateNotFoundException(null, "命令聚合根生成器中获取聚合根对象为空"));

            final Map<BizIdentifierModel<?>, Object> bizIdentifiers = aggregateModel.getBizIdentifiers(aggregate.aggregateRoot());

            // 验证加载的聚合对象的业务ID是否和命令的加载凭证都一致，如果不一致，则报错
            for (BizIdentifierVoucherMember subBizIdentifierMember : command.allBizIdentifierVoucherMembers()) {
                final Object commandSubBizId = subBizIdentifierMember.getValue();
                final String commandSubBizIdName = subBizIdentifierMember.getBizIdentifierName();
                if (!commandSubBizId.equals(bizIdentifiers.get(aggregateModel.getBizIdentifierModel(commandSubBizIdName)))) {
                    throw new IllegalArgumentException("业务ID不匹配");
                }
            }
            // 进行虚拟化
            final SerializedObject<byte[]> beforeHandleSerialize = aggregateRootSerializer.serialize(aggregate.aggregateRoot(), byte[].class);
            final A beforeHandleSnapshot = aggregateRootSerializer.deserialize(beforeHandleSerialize);
            aggregateHandlingMonitor.beforeHandle(commandMessage, beforeHandleSnapshot);
            // 调用命令自身方法
            BusinessMessage<A> businessMessage = GenericBusinessMessage.of(aggregate.aggregateRoot());
            if (aggregate instanceof AggregateLifecycle aggregateLifecycle) {
                aggregateLifecycle.execute(() -> {
                    try {
                        handler.handle(businessMessage, commandMessage.getPayload());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });
            } else {
                handler.handle(businessMessage, commandMessage.getPayload());
            }


            final SerializedObject<byte[]> afterHandleSerialize = aggregateRootSerializer.serialize(aggregate.aggregateRoot(), byte[].class);
            final A afterHandlSnapshot = aggregateRootSerializer.deserialize(afterHandleSerialize);
            // 添加快照
            CurrentMessageTask.get().afterCommit((t) -> {
                aggregateHandlingMonitor.afterCommit(commandMessage, beforeHandleSnapshot, afterHandlSnapshot);
            });
            return null;
        }


    }
}
